home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / bs941029.tgz / bbsx-941029.tar / bbsx / bbs_cmds.c < prev    next >
C/C++ Source or Header  |  1994-10-29  |  56KB  |  2,117 lines

  1. #define _HPUX_SOURCE
  2.  
  3. #include <sys/types.h>
  4.  
  5. #include <stdio.h>
  6.  
  7. #include <ctype.h>
  8. #include <dirent.h>
  9. #include <errno.h>
  10. #include <fcntl.h>
  11. #include <pwd.h>
  12. #include <signal.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <sys/socket.h>
  16. #include <sys/stat.h>
  17. #include <sys/time.h>
  18. #include <sys/wait.h>
  19. #include <termios.h>
  20. #include <time.h>
  21. #include <unistd.h>
  22. #include <ndbm.h>
  23. #include <fnmatch.h>
  24.  
  25. #include "bbs.h"
  26. #include "buildsaddr.h"
  27. #include "strdup.h"
  28. #include "callvalid.h"
  29. #include "lockfile.h"
  30.  
  31. /*---------------------------------------------------------------------------*/
  32.  
  33. const struct cmdtable cmdtable[] = {
  34.  
  35.   "!",          shell_command,          0,      USER,
  36.   "?",          help_command,           0,      USER,
  37.   "ALIAS",    alias_command,        0,    USER,
  38.   "BYE",        bye_command,            0,      USER,
  39.   "CHANGE",    change_command,        3,    ROOT,
  40.   "DELETE",     delete_command,         2,      USER,
  41.   "DESTROY",    destroy_command,        2,      ROOT,
  42.   "DIR",        dir_command,            0,      USER,
  43.   "DISCONNECT", disconnect_command,     0,      USER,
  44.   "ERASE",      delete_command,         2,      USER,
  45.   "EXIT",       quit_command,           0,      USER,
  46.   "F",          f_command,              2,      MBOX,
  47.   "HELP",       help_command,           0,      USER,
  48.   "HIDE",       hide_command,           2,      ROOT,
  49.   "INFO",       info_command,           0,      USER,
  50.   "KILL",       delete_command,         2,      USER,
  51.   "LIST",       list_command,           2,      USER,
  52.   "MAIL",    mail_command,        3,    USER,
  53.   "MOVE",       move_command,           2,      USER,
  54.   "MYBBS",      mybbs_command,          2,      USER,
  55.   "PRINT",      read_command,           2,      USER,
  56.   "QUIT",       quit_command,           0,      USER,
  57.   "READ",       read_command,           2,      USER,
  58.   "REPLY",      reply_command,          2,      USER,
  59.   "RESPOND",    reply_command,          2,      USER,
  60.   "SB",         send_command,           2,      MBOX,
  61.   "SEND",       send_command,           2,      USER,
  62.   "SET",    set_command,        0,    USER,
  63.   "SHELL",      shell_command,          0,      USER,
  64.   "SOURCE",    source_command,        2,    USER,
  65.   "SP",         send_command,           2,      MBOX,
  66.   "STATUS",     status_command,         0,      USER,
  67.   "TELL",    tell_command,        3,    USER,
  68.   "TYPE",       read_command,           2,      USER,
  69.   "UNDELETE",    undelete_command,    2,    USER, 
  70.   "UNERASE",    undelete_command,    2,    USER, 
  71.   "UNSET",    unset_command,        2,    USER,
  72.   "VERSION",    status_command,         0,      USER,
  73.   "WRITE",    write_command,        3,    USER,
  74.   "XCRUNCH",    xcrunch_command,        0,      ROOT,
  75.   "XSCREEN",    xscreen_command,        0,      ROOT,
  76.   "[",          sid_command,            0,      MBOX,
  77.  
  78.   0,            unknown_command,        0,      USER
  79. };
  80.  
  81.  
  82. /*---------------------------------------------------------------------------*/
  83.  
  84. void alias_command(int argc, char **argv)
  85. {
  86.   struct aliastable *p, *new;
  87.   char orig[256], alias[256];
  88.   char *cp;
  89.   char *errstr = "Syntax error. Type ? ALIAS for help.";
  90.   int i;
  91.   
  92.   if (level == MBOX) return;
  93.   
  94.   if (argc==1) {
  95.     p=alias_table;
  96.     while (p) {
  97.       if (!p->is_std) printf("alias: %s  maped to: %s\n",p->orig, p->alias);
  98.       p=p->next;
  99.     }
  100.     return;
  101.   } else 
  102.   {
  103.     if (argc < 3 || *argv[2] != '=') {
  104.       printf("%s\n",errstr);
  105.       return;
  106.     }  
  107.     strcpy(orig,argv[1]);
  108.     *alias=0;
  109.     for(i=3; i < argc; i++) {
  110.       if(i > 3) strcat(alias," ");
  111.       strcat(alias,argv[i]);
  112.     }    
  113.     insert_alias(orig, alias, 0, 0);
  114.   }  
  115. }  
  116.  
  117. /*---------------------------------------------------------------------------*/
  118.  
  119. void bye_command(int argc, char **argv)
  120. {
  121.   puts("BBS terminated.");
  122.   if (level != MBOX) free(alias_table);
  123.   exit(0);
  124. }
  125.  
  126. /*---------------------------------------------------------------------------*/
  127.  
  128. void change_command(int argc, char **argv)     
  129. {
  130.   int i;
  131.   int mesg;
  132.   char line[256];
  133.   struct index index;
  134.   int found = 0;
  135.   int lifetime;
  136.  
  137.   for (i = 2; i < argc; i++) {
  138.     if ((mesg = atoi(argv[i])) > 0 && get_index(mesg, &index) && 
  139.          !(index.flags & DELETED)) {
  140.        found = 1;
  141.        strlwc(argv[1]);
  142.        if (!strcmp("#", argv[1]) || !strncmp(argv[1],"lifetime",strlen(argv[1]))) {
  143.           lifetime = ((index.lifetime_h << 8) & 0xff00) + (index.lifetime_l & 0xff) - 1;
  144.  
  145.           printf("Message #%d Lifetime ", mesg);
  146.           if (lifetime >= 0) {
  147.             printf("[%d] : ", lifetime);
  148.           } else {
  149.             printf("[expired] : ");
  150.           }  
  151.           *line=0;
  152.           if (!getstring(line)) exit(1);
  153.           if (*line) {
  154.              if (!Strncasecmp(line,"expired",strlen(line))) 
  155.                 lifetime = -1;
  156.              else   
  157.                 lifetime = Atoi(line);
  158.              index.lifetime_h = (lifetime + 1) >> 8;
  159.              index.lifetime_l = (lifetime + 1);
  160.           }
  161.        }else
  162.        if (!strcmp("$", argv[1]) || !strncmp(argv[1],"bid",strlen(argv[1]))) {
  163.           printf("Message #%d BID [%s] : ", mesg, index.bid);
  164.           *line=0;
  165.           if(!getstring(line)) exit(1);
  166.           line[LEN_BID] = 0;
  167.           if (*line) {
  168.              strupc(line);
  169.              strcpy(index.bid, line);
  170.           }
  171.        }else 
  172.        if (!strcmp(">", argv[1]) || !strncmp(argv[1],"to",strlen(argv[1]))) {
  173.           printf("Message #%d TO [%s] : ", mesg, index.to);
  174.           *line=0;
  175.           if(!getstring(line)) exit(1);
  176.           line[LEN_TO] = 0;
  177.           if (*line) {
  178.              strupc(line);
  179.              strcpy(index.to, line);
  180.           }
  181.        }else
  182.        if (!strcmp("<", argv[1]) || !strncmp(argv[1],"from",strlen(argv[1]))) {
  183.           printf("Message #%d FROM [%s] : ", mesg, index.from);
  184.           *line=0;
  185.           if(!getstring(line)) exit(1);
  186.           line[LEN_FROM] = 0;
  187.           if (*line) {
  188.              strupc(line);
  189.              if (callvalid(line)) { 
  190.                 strcpy(index.from, line);
  191.              } else
  192.              {
  193.                printf("%s is not a valid call.\n");
  194.              }     
  195.           }
  196.        }else
  197.        if (!strcmp("@", argv[1]) || !strncmp(argv[1],"at",strlen(argv[1]))) {
  198.           printf("Message #%d AT [%s] : ", mesg, index.at);
  199.           *line=0;
  200.           if(!getstring(line)) exit(1);
  201.           line[LEN_AT] = 0;
  202.           if (*line) {
  203.              strupc(line);
  204.              strcpy(index.at, line);
  205.           }
  206.        }else
  207.        if (!Strncasecmp(argv[1],"Subject",strlen(argv[1]))) {
  208.           printf("Message #%d Subject [%s] : ", mesg, index.subject);
  209.           *line=0;
  210.           if(!getstring(line)) exit(1);
  211.           line[LEN_SUBJECT] = 0;
  212.           if (*line) {
  213.              strcpy(index.subject, line);
  214.           }
  215.        }else
  216.        {
  217.          printf("%s ? What's that ?\n", argv[1]);
  218.          return;
  219.        } 
  220.        if (lseek(fdindex, -sizeof(struct index), SEEK_CUR) < 0) halt();
  221.        if (write(fdindex, &index, sizeof(struct index)) !=
  222.                  sizeof(struct index)) halt();
  223.                             
  224.     }        
  225.   } 
  226.   if (!found) {
  227.      printf("No message found.\n");
  228.   }
  229. }
  230.  
  231. /*---------------------------------------------------------------------------*/
  232.  
  233. void delete_command(int argc, char **argv)     
  234. {
  235.  
  236.   int i;
  237.   int mesg;
  238.   char line[256];
  239.   struct index index;
  240.   struct mail *mail;
  241.   int max_mesg;
  242.   int found = 0;
  243.  
  244.   max_mesg = get_highest_mesg(argc,argv);
  245.   for (mesg = get_lowest_mesg(argc,argv); mesg <= max_mesg; mesg++)
  246.     if (mesg_in_command(argc, argv, mesg, &index) &&
  247.          !(index.flags & DELETED)) {
  248.       found = 1;   
  249.       if (level == ROOT                 ||
  250.       calleq(index.from, user.name) ||
  251.       calleq(index.to, user.name)) {
  252.         index.date = time((long *) 0);
  253.         if (strcmp(index.at, Myhostname) && level != ROOT) {
  254.           mail=alloc_mail();
  255.           strcpy(mail->to,"E@THEBOX");
  256.           strcpy(mail->orig_to,"E@THEBOX");
  257.           strcpy(mail->from, user.name);
  258.           *mail->bid=0;
  259.           strcpy(mail->subject,index.bid);  
  260.           route_mail(mail);
  261.           free_mail(mail);
  262.           get_index(mesg,&index);
  263.         }
  264.         strcpy(index.to,"B");
  265.         strcpy(index.at,Myhostname);
  266.         if (lseek(fdindex, -sizeof(struct index), SEEK_CUR) < 0) halt();
  267.         if (write(fdindex, &index, sizeof(struct index)) !=
  268.             sizeof(struct index)) halt();
  269.         if (level == ROOT )
  270.           printf("Message %d is now in Backuparea.\n", mesg);
  271.         else
  272.           printf("Message %d deleted.\n", mesg);
  273.       } else
  274.           printf("Message %d not deleted:  Permission denied.\n", mesg);
  275.     }
  276.   if (!found) {
  277.      printf("No message found.\n");
  278.   }      
  279. }
  280.  
  281.  
  282. /*---------------------------------------------------------------------------*/
  283.  
  284. void destroy_command(int argc, char **argv) 
  285. {
  286.  
  287.   int i;
  288.   int mesg;
  289.   struct index index;
  290.   int max_mesg;
  291.   int found = 0;
  292.  
  293.   max_mesg = get_highest_mesg(argc,argv);
  294.   for (mesg = get_lowest_mesg(argc,argv); mesg <= max_mesg; mesg++)
  295.     if (mesg_in_command(argc, argv, mesg, &index) && 
  296.          !(index.flags & DELETED)) {
  297.       found = 1;   
  298.       if (level == ROOT                 ||
  299.       calleq(index.from, user.name) ||
  300.       calleq(index.to, user.name)) {
  301.     if (unlink(getfilename(mesg))) halt();
  302.     index.flags = index.flags | DELETED;
  303.     if (lseek(fdindex, -sizeof(struct index), SEEK_CUR) < 0) halt();
  304.     if (write(fdindex, &index, sizeof(struct index)) != sizeof(struct index)) halt();
  305.     printf("Message %d deleted.\n", mesg);
  306.       } else
  307.     printf("Message %d not deleted:  Permission denied.\n", mesg);
  308.     }
  309.   if (!found) {
  310.      printf("No message found.\n");
  311.   }        
  312. }
  313. /*---------------------------------------------------------------------------*/
  314.  
  315. void dir_command(int argc, char **argv)
  316. {
  317.  
  318.   int n, cmp, i;
  319.   struct dir_entry *head, *curr, *prev;
  320.   struct index *pi, index[1000];
  321.   int match = 0;
  322.  
  323.   head = 0;
  324.   cmp = 0;
  325.   if (lseek(fdindex, 0L, SEEK_SET)) halt();
  326.   for (; ; ) {
  327.     n = read(fdindex, pi = index, 1000 * sizeof(struct index)) / sizeof(struct index);
  328.     if (n < 1) break;
  329.     for (; n; n--, pi++) {
  330.       if (argc > 1) {   
  331.          match = 0;
  332.          for(i=1; i < argc && !match; i++) {
  333.             match = (fnmatch(argv[i], pi->to, FNM_CASEFOLD) != FNM_NOMATCH);
  334.          }   
  335.       }
  336.       else match = 1;
  337.          
  338.       if (read_allowed(pi) && match)
  339.     for (prev = 0, curr = head; ; ) {
  340.       if (!curr) {
  341.         curr = malloc(sizeof(*curr));
  342.         curr->left = curr->right = 0;
  343.         curr->count = 1;
  344.         strcpy(curr->to, pi->to);
  345.         if (!prev)
  346.           head = curr;
  347.         else if (cmp < 0)
  348.           prev->left = curr;
  349.         else
  350.           prev->right = curr;
  351.         break;
  352.       }
  353.       if (!(cmp = strcmp(pi->to, curr->to))) {
  354.         curr->count++;
  355.         break;
  356.       }
  357.       prev = curr;
  358.       curr = (cmp < 0) ? curr->left : curr->right;
  359.     }
  360.     }    
  361.   }
  362.   dir_column = 0;
  363.   dir_print(head);
  364.   if (!stopped && (dir_column % 5)) putchar('\n');
  365. }
  366.  
  367. /*---------------------------------------------------------------------------*/
  368.  
  369. void disconnect_command(int argc, char **argv)
  370. {
  371.   free(alias_table);
  372.   if (user.seq < highest_on_start) user.seq = highest_on_start;
  373.   if (level != MBOX) {
  374.     put_seq();
  375.     free(alias_table);
  376.   }  
  377.   puts("Disconnecting...");
  378.   kill(0, 1);
  379.   exit(0);
  380. }
  381.  
  382. /*---------------------------------------------------------------------------*/
  383.  
  384. void f_command(int argc, char **argv)
  385. {
  386.  
  387.   int do_not_exit;
  388.   struct index index;
  389.   int count=0;
  390.  
  391.   do_not_exit=doforward;
  392.  
  393.   forward_mail();
  394.  
  395.   get_seq();
  396.  
  397.   if (!get_index(user.seq, &index))
  398.     if (lseek(fdindex, 0L, SEEK_SET)) halt();
  399.   
  400.   while (read(fdindex, &index, sizeof(struct index)) == sizeof(struct index)) {
  401.     if (!(count % 10)) {
  402.       forward_mail();
  403.     }
  404.     count++;
  405.     if (!(index.flags & DELETED)      &&
  406.     index.mesg > user.seq         &&
  407.     !calleq(index.at, myhostname) &&
  408.     !host_in_header(getfilename(index.mesg), user.name)) {
  409.       forward_message(&index, getfilename(index.mesg), index.at, 0);
  410.       do_not_exit = 1;
  411.     }
  412.     if (user.seq < index.mesg) {
  413.       user.seq = index.mesg;
  414.       put_seq();
  415.     }
  416.   }
  417.   if (!do_not_exit) exit(0);
  418.   close(fdseq);
  419.   putchar('F');
  420. }
  421.  
  422.  
  423. /*---------------------------------------------------------------------------*/
  424.  
  425. void help_command(int argc, char **argv)
  426. {
  427.  
  428.   FILE *fp;
  429.   char line[1024];
  430.   int i;
  431.   int state;
  432.   struct aliastable *p;
  433.  
  434.   if (argc < 2) {
  435.     puts("Commands may be abbreviated.  Commands are:");
  436.     i=0; 
  437.     p=alias_table;
  438.     while(p) {
  439.       if (level >= p->level && p->is_std)
  440.     printf((i++ % 6) < 5 ? "%-13s" : "%s\n", p->orig);
  441.       p=p->next;
  442.     }    
  443.     if (i % 6) putchar('\n');
  444.     return;
  445.   }
  446.   if (!(fp = fopen(helpfile, "r"))) {
  447.     puts("Sorry, cannot open help file.");
  448.     return;
  449.   }
  450.   if (!Strcasecmp(argv[1], "all")) {
  451.     while (!stopped && fgets(line, sizeof(line), fp))
  452.       if (*line != '^') fputs(line, stdout);
  453.   } else {
  454.     state = 0;
  455.     while (!stopped && fgets(line, sizeof(line), fp)) {
  456.       strtrim(line);
  457.       if (state == 0 && *line == '^' && !Strcasecmp(line + 1, argv[1]))
  458.     state = 1;
  459.       if (state == 1 && *line != '^')
  460.     state = 2;
  461.       if (state == 2) {
  462.     if (*line == '^') break;
  463.     puts(line);
  464.       }
  465.     }
  466.     if (!stopped && state < 2)
  467.       printf("Sorry, there is no help available for '%s'.\n", argv[1]);
  468.   }
  469.   fclose(fp);
  470. }
  471.  
  472. /*---------------------------------------------------------------------------*/
  473.  
  474. void hide_command(int argc, char **argv)
  475. {
  476.  
  477.   int i;
  478.   int mesg;
  479.   char line[90];
  480.   struct index index;
  481.   int max_mesg;
  482.   int found = 0;
  483.  
  484.   max_mesg = get_highest_mesg(argc,argv);
  485.   for (mesg = get_lowest_mesg(argc,argv); mesg <= max_mesg; mesg++)
  486.     if (mesg_in_command(argc, argv, mesg, &index) &&
  487.          !(index.flags & DELETED)) {
  488.       found = 1;   
  489.       strcpy(index.to,"A");
  490.       strcpy(index.at,myhostname);strupc(index.at);
  491.       if (lseek(fdindex, -sizeof(struct index), SEEK_CUR) < 0) halt();
  492.       if (write(fdindex, &index, sizeof(struct index)) != sizeof(struct index)) halt();
  493.         printf("Message %d is now hidden.\n", mesg);
  494.     }
  495.   if (!found) {
  496.      printf("No message found.\n");
  497.   }
  498. }
  499.  
  500.  
  501. /*---------------------------------------------------------------------------*/
  502.  
  503. void info_command(int argc, char **argv)
  504. {
  505.  
  506.   FILE *fp;
  507.   int c;
  508.  
  509.   if (!(fp = fopen(infofile, "r"))) {
  510.     puts("Sorry, cannot open info file.");
  511.     return;
  512.   }
  513.   while (!stopped && (c = getc(fp)) != EOF) putchar(c);
  514.   fclose(fp);
  515. }
  516.  
  517. /*---------------------------------------------------------------------------*/
  518.  
  519. #define nextarg(name)     \
  520.   if (++i >= argc) {      \
  521.     errors++;             \
  522.     printf(errstr, name); \
  523.     return;               \
  524.   }
  525.  
  526. #define MAX_MESG 999999
  527.  
  528. void list_command(int argc, char **argv)
  529. {
  530.   char *at = 0;
  531.   char *bid = 0;
  532.   char *errstr = "The %s option requires an argument.  Type ? LIST for help.\n";
  533.   char *from = 0;
  534.   char *subject = 0;
  535.   char *to = 0;
  536.   int count = MAX_MESG;
  537.   int found = 0;
  538.   int i;
  539.   int max = MAX_MESG;
  540.   int min = 1;
  541.   int update_seq = 0;
  542.   size_t len;
  543.   struct index index;
  544.   char buffer[LEN_SUBJECT+6];
  545.   static struct termio save;
  546.   int nr_list;
  547.  
  548.   if (interface_type != wampes)
  549.     count = 1;
  550.   nr_list = max_list;
  551.  
  552.   for (i = 1; i < argc; i++) {
  553.     len = strlen(strlwc(argv[i]));
  554.     if (!strcmp("$", argv[i]) || !strncmp("bid", argv[i], len)) {
  555.       nextarg("BID");
  556.       bid = strupc(argv[i]);
  557.     } else if (!strcmp("<", argv[i]) || !strncmp("from", argv[i], len)) {
  558.       nextarg("FROM");
  559.       from = strupc(argv[i]);
  560.     } else if (!strcmp(">", argv[i]) || !strncmp("to", argv[i], len)) {
  561.       nextarg("TO"); 
  562.       to = strupc(argv[i]);
  563.       strcpy(last_board,to);
  564.     } else if (!strcmp("@", argv[i]) || !strncmp("at", argv[i], len)) {
  565.       nextarg("AT");
  566.       at = strupc(argv[i]);
  567.     } else if (!strcmp("+", argv[i]) && (interface_type != wampes)) {
  568.       nextarg("+");
  569.       count = Atoi(argv[i]);
  570.       nr_list = MAX_MESG;
  571.     } else if (!strcmp("-", argv[i])) {
  572.       if (Atoi(argv[i-1]) && !Atoi(argv[i+1])) {    /* z.B.: 3- */
  573.         min = Atoi(argv[i-1]);
  574.         max = MAX_MESG;
  575.         nr_list = MAX_MESG;
  576.       } else 
  577.       if (!Atoi(argv[i-1]) && Atoi(argv[i+1])) {     /* z.B.: -3 */
  578.         nextarg("-");
  579.         min = 0;
  580.         max = Atoi(argv[i]);
  581.         nr_list = MAX_MESG;
  582.       } else 
  583.       if (Atoi(argv[i-1]) && Atoi(argv[i+1])) {        /* z.B.: 3-4 */
  584.         min = Atoi(argv[i-1]);
  585.         nextarg("-");
  586.         max = Atoi(argv[i]);
  587.         nr_list = MAX_MESG;
  588.       }     
  589.     } else if (!strncmp("count", argv[i], len)) {
  590.       nextarg("COUNT");
  591.       count = Atoi(argv[i]);
  592.       nr_list = MAX_MESG;
  593.     } else if (!strncmp("all", argv[i], len)) {
  594.       if (i+1 == argc)
  595.          to = strupc(argv[i]);
  596.       nr_list = MAX_MESG;
  597.     } else if (!strncmp("new", argv[i], len)) {
  598.       min = user.seq + 1;
  599.       update_seq = (argc == 2 && level == USER);
  600.     } else if (!strncmp("max", argv[i], len)) {
  601.       nextarg("MAX");
  602.       max = Atoi(argv[i]);
  603.     } else if (!strncmp("min", argv[i], len)) {
  604.       nextarg("MIN");
  605.       min = Atoi(argv[i]);
  606.       nr_list = MAX_MESG;
  607.     } else if (!strncmp("subject", argv[i], len)) {
  608.       nextarg("SUBJECT");
  609.       subject = argv[i];
  610.       nr_list = MAX_MESG;
  611.     } else if (Atoi(argv[i])) {
  612.       min = max = Atoi(argv[i]);
  613.     } else {
  614.       to = strupc(argv[i]);
  615.       strcpy(last_board,to);
  616.     }
  617.   }
  618.   
  619.   if (is_tell_user)
  620.     if (count && count > 25)
  621.       count = 25;
  622.   
  623.   if ((level == USER) && (!last_board[1])) {
  624.     *last_board = 0;
  625.   }  
  626.   if (interface_type == wampes) {
  627.     if (!to) *last_board= 0;
  628.   } else 
  629.     if (!count) 
  630.       if (*last_board && !to) 
  631.         to=strupc(last_board);
  632.       else 
  633.         if (!*last_board && !to) {
  634.           strcpy(last_board,user.name);
  635.           to = strupc(last_board);
  636.         }  
  637.       
  638.   ioctl(0,TCGETA, &save);
  639.   save.c_cc[VINTR] = escape_char;
  640.   ioctl(0,TCSETA, &save);
  641.   
  642.   if (to) {
  643.      strcpy(buffer,to);
  644.      getalias(buffer);
  645.      if (strcmp(to, buffer)) {
  646.         printf("\n *** WARNING ***\n");
  647.         printf(" *** Board %s is not available. Bulletins are stored in %s. ***\n\n\n", to, buffer);
  648.         strcpy(to, buffer);
  649.      }
  650.   }      
  651.   
  652.   if (lseek(fdindex, -sizeof(struct index), SEEK_END) >= 0) {
  653.     for (; ; ) {
  654.       if (stopped) {
  655.         *last_board = 0;
  656.         return;
  657.       }  
  658.       if (read(fdindex, &index, sizeof(struct index)) != sizeof(struct index)) halt();
  659.       if (index.mesg < min) break;
  660.       if (index.mesg <= max                            &&
  661.       read_allowed(&index)                         &&
  662.       (!bid      || !strcmp(index.bid, bid))       &&
  663.       (!from     || !strcmp(index.from, from))     &&
  664.       (!to       || !strcmp(index.to, to))         &&
  665.       (!at       || !strcmp(index.at, at))         &&
  666.       (!subject  || strcasepos(index.subject, subject))) {
  667.     if (!found) {
  668.       puts("  Msg#  Size To      @ BBS     From     Date    Subject");
  669.       found = 1;
  670.     } else
  671.       found++;
  672.     if (index.flags & BINARY) {
  673.       sprintf(buffer,"(BIN) %s",index.subject);
  674.     } else
  675.     {
  676.       strcpy(buffer,index.subject);
  677.     }  
  678.     printf("%6d %5ld %-8s%c%-8s %-8s %-7.7s %.31s\n",
  679.            index.mesg,
  680.            index.size,
  681.            index.to,
  682.            *index.at ? '@' : ' ',
  683.            index.at,
  684.            index.from,
  685.            timestr(index.date),
  686.            buffer);
  687.     if (update_seq && user.seq < index.mesg) {
  688.       user.seq = index.mesg;
  689.     }
  690.     if (--count <= 0) break;
  691.     if (is_tell_user && found == 50) break;
  692.       }
  693.       if (lseek(fdindex, -2L * sizeof(struct index), SEEK_CUR) < 0) break;
  694.     if (--nr_list <=0) break;  
  695.     }
  696.   }
  697.   if (!found) {
  698.     puts(update_seq ?
  699.      "No new messages since last LIST NEW command." :
  700.      "No matching message found.");
  701.     *last_board = 0;
  702.   }  
  703.   save.c_cc[VINTR] = orig_escape;
  704.   ioctl(0,TCSETA, &save);
  705. }
  706.  
  707. #undef MAX_MESG
  708. #undef nextarg
  709.  
  710.  
  711. /*---------------------------------------------------------------------------*/
  712.  
  713. #define nextarg(name)       \
  714.   if (++i >= argc)          \
  715.     {                       \
  716.       errors++;             \
  717.       printf(errstr, name) ;  \
  718.       free_mail(mail);      \
  719.       return;               \
  720.     }
  721.  
  722.  
  723. void mail_command(int argc, char **argv)
  724. {
  725.   
  726.   char *errstr = "The %s option requires an argument.  Type ? MAIL for help.\n";
  727.   FILE *fp;
  728.   char buffer[1024];
  729.   char to[512];
  730.   int mesg;
  731.   struct index index;
  732.   struct mail *mail;
  733.   int i;
  734.   int found = 0;
  735.  
  736.   if (argc < 3) {
  737.     printf("Syntax error. Type ? MAIL for help.\n");
  738.     return;
  739.   }
  740.   strcpy(to,argv[1]);
  741.   for(i = 2; i < argc; i++) {
  742.     if (!strcmp("@", argv[i])) {
  743.       nextarg("@");
  744.       strcat(to,"@");
  745.       strcat(to, argv[i]);
  746.     } else
  747.     if ((mesg = Atoi(argv[i])) > 0 && get_index(mesg, &index) && 
  748.          read_allowed(&index)) {
  749.        found = 1;  
  750.        if (level == ROOT                 ||
  751.        calleq(index.from, user.name)) {
  752.          mail = alloc_mail(); 
  753.          if (level == ROOT ) 
  754.            strcpy(mail->from, index.from);
  755.          else  
  756.            strcpy(mail->from, user.name);
  757.          strcpy(mail->to, to);
  758.          strcpy(mail->orig_to, to);
  759.          strcpy(mail->subject, index.subject);
  760.          mail->lifetime= index.lifetime_h << 8 + index.lifetime_l;
  761.          *mail->bid = 0;
  762.          *mail->mid = 0;
  763.          strlwc(mail->to);
  764.          strlwc(mail->orig_to);
  765.          if (!(fp = fopen(getfilename(mesg), "r"))) halt();
  766.          while (fgets(buffer, sizeof(buffer), fp)) {
  767.            buffer[strlen(buffer)-1] = 0;   
  768.        append_line(mail, buffer);
  769.          }
  770.          printf("Sending message to %s.\n", mail->to);
  771.          route_mail(mail);
  772.        } 
  773.        else 
  774.          printf("Message: %s - permission denied.\n",argv[i]);   
  775.     }
  776.   }   
  777.   if (!found) {
  778.      printf("No message found.\n");
  779.   }
  780.   return;
  781.  
  782. #undef nextarg   
  783.  
  784. /*---------------------------------------------------------------------------*/
  785. #define nextarg(name)     \
  786.   if (++i >= argc) {      \
  787.     errors++;             \
  788.     printf(errstr, name); \
  789.     return;               \
  790.   }
  791.  
  792. void move_command(int argc, char **argv)
  793. {
  794.  
  795.   char *errstr = "The %s option requires an argument.  Type ? MOVE for help.\n";
  796.   int i,len;
  797.   int mesg;
  798.   struct index index;
  799.   char forward[80];
  800.   int found = 0;
  801.  
  802.   
  803.   *forward = 0;
  804.   for (i = 1; i < argc; i++){
  805.     len = strlen(strupc(argv[i]));
  806.     if (!strcmp("TO", argv[i])) {
  807.       nextarg("TO");
  808.       strcpy(forward,strupc(argv[i]));
  809.     } else if (!strcmp(">", argv[i])) {
  810.       nextarg("TO");
  811.       strcpy(forward,strupc(argv[i]));
  812.     }
  813.     getalias(forward);
  814.     if ((mesg = Atoi(argv[i])) > 0 && get_index(mesg, &index) && 
  815.         !(index.flags & DELETED)) {
  816.       found = 1;  
  817.       if (level == ROOT             ||
  818.       calleq(index.from, user.name) ||
  819.       calleq(index.to, user.name)) {
  820.         if (lseek(fdindex, -sizeof(struct index), SEEK_CUR) < 0) halt();
  821.         if (!strcmp(forward,""))
  822.         {
  823.           puts("No forward-area defined!");
  824.           return ;
  825.         }
  826.         if (strlen(forward) == 1 && level != ROOT)
  827.         {
  828.           printf("Message %d not moved:  Permission denied.\n", mesg);
  829.           return ;
  830.         }
  831.         else {
  832.           strcpy(index.to,forward);
  833.           if (!forward_allowed(&index,myhostname)) {
  834.             printf("Message %d not moved:  Permission denied.\n", mesg);         
  835.             return ;
  836.           }  
  837.           if (write(fdindex, &index, sizeof(struct index)) !=
  838.               sizeof(struct index)) halt();
  839.           printf("Message %d moved.\n", mesg);
  840.         }  
  841.       } else
  842.           printf("Message %d not moved:  Permission denied.\n", mesg);
  843.     }
  844.     else
  845.       if(Atoi(argv[i]))
  846.         printf("No such message: '%s'.\n", argv[i]);
  847.   }
  848.   if (!found) {
  849.      printf("No message found.\n");
  850.   }
  851. }
  852.  
  853. #undef nextarg
  854.  
  855.  
  856. /*---------------------------------------------------------------------------*/
  857.  
  858. void mybbs_command(int argc, char **argv)
  859. {
  860.   struct mail *mail;
  861.  
  862.   if (!callvalid(strupc(argv[1]))) {
  863.     printf("Invalid call '%s'.\n", argv[1]);
  864.     return;
  865.   }
  866.   mail = alloc_mail();
  867.   strcpy(mail->from, user.name);
  868.   strcpy(mail->to, "m@thebox");
  869.   strcpy(mail->orig_to,"m@thebox");
  870.   sprintf(mail->subject, "%s %ld", argv[1], time((long *) 0));
  871.   append_line(mail, "");
  872.   printf("Setting MYBBS to %s.\n", argv[1]);
  873.   route_mail(mail);
  874. }
  875.  
  876. /*---------------------------------------------------------------------------*/
  877.  
  878. void quit_command(int argc, char **argv)
  879. {
  880.   
  881.   if (user.seq < highest_on_start) user.seq = highest_on_start;
  882.   if (level != MBOX) {
  883.     put_seq();
  884.     free(alias_table);
  885.   }  
  886.   puts("BBS terminated.");
  887.   exit(0);
  888. }
  889. /*---------------------------------------------------------------------------*/
  890.  
  891. void read_command(int argc, char **argv)
  892. {
  893.  
  894.   FILE *fp;
  895.   char *p;
  896.   char buf[1024];
  897.   char path[1024];
  898.   int i;
  899.   int inheader;
  900.   int mesg;
  901.   struct index index;
  902.   struct log log;
  903.   static struct termio save;
  904.   int max_mesg;
  905.   int bytes=0;
  906.   int fdlog;
  907.   int found = 0;
  908.   struct tm *tm;
  909.   long now;
  910.   char logfile[80];
  911.  
  912.   ioctl(0,TCGETA, &save);
  913.   save.c_cc[VINTR] = escape_char;
  914.   ioctl(0,TCSETA, &save);
  915.   
  916.   now = time(0L);
  917.   tm=gmtime(&now);
  918.   sprintf(logfile,"%s%02d%02d.log",LOGFILE,tm->tm_year, tm->tm_mon); 
  919.   
  920.   max_mesg = get_highest_mesg(argc,argv);
  921.   for (mesg = get_lowest_mesg(argc,argv); mesg <= max_mesg; mesg++)
  922.     if (mesg_in_command(argc, argv, mesg, &index) && read_allowed(&index)) {
  923.       found = 1;
  924.       if (!(fp = fopen(getfilename(mesg), "r"))) halt();
  925.       if (log_reading && level == USER) bytes = 0;
  926.       printf("\nMsg# %d   To: %s%s%s   From: %s   Date: %s\n",
  927.          index.mesg,
  928.          index.to,
  929.          *index.at ? " @" : "",
  930.          index.at,
  931.          index.from,
  932.          timestr(index.date));
  933.       if (*index.subject) printf("Subject: %s\n", index.subject);
  934.       if (*index.bid) printf("Bulletin ID: %s\n", index.bid);
  935.       if (level != MBOX) printf("\n");
  936.       fflush(stdout);
  937.       *path = 0;
  938.       inheader = 1;
  939.  
  940.       while (fgets(buf, sizeof(buf), fp)) {
  941.     if (stopped) {
  942.       fclose(fp);
  943.       return;
  944.     }
  945.     if (inheader) {
  946.       if (p = get_host_from_header(buf)) {
  947.         strcat(path, *path ? "!" : "Path: ");
  948.         strcat(path, p);
  949.         continue;
  950.       }
  951.       if (*path) puts(path);
  952.       inheader = 0;
  953.     }
  954. #ifdef BOXBIN    
  955.     if (!strncmp(buf,"#UUENCODE#",10) && binary_allowed)
  956.     {
  957.       sscanf(buf,"#UUENCODE%s",path);
  958.       if (uudecode(fp,path)) halt();
  959.       fclose(fp);
  960.       
  961.       save.c_cc[VINTR] = orig_escape;
  962.           ioctl(0,TCSETA, &save);
  963.       return;
  964.     }
  965. #endif    
  966.     fputs(buf, stdout);
  967.     if (log_reading) {
  968.       bytes += strlen(buf);
  969.       bytes++;
  970.     }  
  971.       }
  972.       putchar('\n');
  973.       fclose(fp);
  974.       if(log_reading && bytes && level == USER) {
  975.         strcpy(log.to, index.to);
  976.         log.bytes=bytes;
  977.         log.uid = user.uid;
  978.         log.time = time(0L);
  979.         if ((fdlog = lock_file(LOCKFILE, 0)) < 0) halt();
  980.         if (lseek(fdlog, 0L, SEEK_END) < 0) halt();
  981.         if (write(fdlog, &log, sizeof(struct log)) != sizeof(struct log)) halt();
  982.         close(fdlog);
  983.       }
  984.     } 
  985.  
  986.   save.c_cc[VINTR] = orig_escape;
  987.   ioctl(0,TCSETA, &save);
  988.   if (!found) {
  989.      printf("No message found.\n");
  990.   }
  991. }
  992.  
  993.  
  994. /*---------------------------------------------------------------------------*/
  995.  
  996. void reply_command(int argc, char **argv)
  997. {
  998.  
  999.   FILE *fp;
  1000.   char *host;
  1001.   char *mesgstr;
  1002.   char *p;
  1003.   static char line[1024];
  1004.   int all;
  1005.   int i;
  1006.   int mesg;
  1007.   struct index index;
  1008.   static struct mail *mail;
  1009.  
  1010.   mesg = all = 0;
  1011.   mesgstr = 0;
  1012.   for (i = 1; i < argc; i++)
  1013.     if (!Strcasecmp(argv[i], "all"))
  1014.       all = 1;
  1015.     else
  1016.       mesg = Atoi(mesgstr = argv[i]);
  1017.   if (!mesgstr) {
  1018.     puts("No message number specified.");
  1019.     return;
  1020.   }
  1021.   if (mesg < 1 || !get_index(mesg, &index) || !read_allowed(&index)) {
  1022.     printf("No such message: '%s'.\n", mesgstr);
  1023.     return;
  1024.   }
  1025.   mail = alloc_mail();
  1026.   strcpy(mail->from, user.name);
  1027.   if (all) {
  1028.     strcpy(mail->to, index.orig_to);
  1029.     strcpy(mail->orig_to, index.orig_to);
  1030.     if (*index.at) {
  1031.       strcat(mail->to, "@");
  1032.       strcat(mail->to, index.at);
  1033.       strcat(mail->orig_to, "@");
  1034.       strcat(mail->orig_to, index.at);
  1035.     }
  1036.   } else {
  1037.     strcpy(mail->to, index.from);
  1038.     strcpy(mail->orig_to, index.from);
  1039.     if (!(fp = fopen(getfilename(mesg), "r"))) halt();
  1040.     for (host = 0; fgets(line, sizeof(line), fp); host = p)
  1041.       if (!(p = get_host_from_header(line))) break;
  1042.     fclose(fp);
  1043.     if (host) {
  1044.       strcat(mail->to, "@");
  1045.       strcat(mail->to, host);
  1046.       strcat(mail->orig_to, "@");
  1047.       strcat(mail->orig_to, host);
  1048.     }
  1049.   }
  1050.   strlwc(mail->to);
  1051.   strlwc(mail->orig_to);
  1052.   for (p = index.subject; ; ) {
  1053.     while (isspace(uchar(*p))) p++;
  1054.     if (Strncasecmp(p, "Re:", 3)) break;
  1055.     p += 3;
  1056.   }
  1057.   sprintf(mail->subject, "Re:  %s", p);
  1058.   printf("To: %s\n", mail->to);
  1059.   printf("Subject: %s\n", mail->subject);
  1060.   puts("Enter message: (terminate with ^Z or ***END)");
  1061.   for (; ; ) {
  1062.     if (!getstring(line)) exit(1);
  1063.     if (!strncmp(line,"#BIN#",5)) {
  1064. #ifdef BOXBIN    
  1065.       mail->bin = 1;
  1066.       i= send_binary(mail,line);
  1067.       if( !i ) {
  1068.         break ;
  1069.       }  else
  1070.       if (i == 1) 
  1071.       {
  1072.         mail->bin = 0;
  1073.       } else
  1074.       {
  1075.         free_mail(mail);
  1076.         return;
  1077.       } 
  1078. #else
  1079.       puts("#NO#");
  1080.       free_mail(mail);
  1081.       return;
  1082. #endif            
  1083.     }
  1084.     if (stopped) {
  1085.       free_mail(mail);
  1086.       return;
  1087.     }
  1088.     if (*line == '\032') break;
  1089.     if (!Strncasecmp(line, "***end", 6)) break;
  1090.     append_line(mail, line);
  1091.     if (strchr(line, '\032')) break;
  1092.   }
  1093.   printf("Sending message to %s.\n", mail->to);
  1094.   route_mail(mail);
  1095. }
  1096.  
  1097. /*---------------------------------------------------------------------------*/
  1098.  
  1099. void shell_command(int argc, char **argv)
  1100. {
  1101.  
  1102.   char command[2048];
  1103.   int i;
  1104.   int status;
  1105.   pid_t pid;
  1106.  
  1107.   switch (pid = fork()) {
  1108.   case -1:
  1109.     puts("Sorry, cannot fork.");
  1110.     break;
  1111.   case 0:
  1112.     setgid(user.gid);
  1113.     setuid(user.uid);
  1114.     for (i = open_max() - 1; i >= 3; i--) close(i);
  1115.     chdir(user.cwd);
  1116.     *command = 0;
  1117.     for (i = 1; i < argc; i++) {
  1118.       if (i > 1) strcat(command, " ");
  1119.       strcat(command, argv[i]);
  1120.     }
  1121.     if (*command)
  1122.       execl(user.shell, user.shell, "-c", command, (char *) 0);
  1123.     else
  1124.       execl(user.shell, user.shell, (char *) 0);
  1125.     _exit(127);
  1126.     break;
  1127.   default:
  1128.     signal(SIGINT,  SIG_IGN);
  1129.     signal(SIGQUIT, SIG_IGN);
  1130.     while (waitpid(pid, &status, 0) != pid) ;
  1131.     signal(SIGINT,  interrupt_handler);
  1132.     signal(SIGQUIT, interrupt_handler);
  1133.     break;
  1134.   }
  1135. }
  1136.  
  1137. /*---------------------------------------------------------------------------*/
  1138.  
  1139. #define nextarg(name)       \
  1140.   if (++i >= argc)          \
  1141.     {                       \
  1142.       errors++;             \
  1143.       if (level == MBOX) puts("NO"); else printf(errstr, name) ;  \
  1144.       free_mail(mail);      \
  1145.       return;               \
  1146.     }
  1147.  
  1148. void send_command(int argc, char **argv)
  1149. {
  1150.  
  1151.   char *errstr = "The %s option requires an argument.  Type ? SEND for help.\n";
  1152.   char *p;
  1153.   char at[1024];
  1154.   static char line[1024];
  1155.   char path[1024];
  1156.   int check_header = 1;
  1157.   int i;
  1158.   int unique;
  1159.   static struct mail *mail;
  1160.  
  1161.   mail = alloc_mail();
  1162.   *at = *path = 0;
  1163.   for (i = 1; i < argc; i++)
  1164.     if (!strcmp("#", argv[i])) {
  1165.       nextarg("#");
  1166.       mail->lifetime = Atoi(argv[i]);
  1167.     } else if (!strcmp("$", argv[i])) {
  1168.       nextarg("$");
  1169.       if (level > USER)
  1170.         strcpy(mail->bid, argv[i]);
  1171.     } else if (!strcmp("<", argv[i])) {
  1172.       nextarg("<");
  1173.       if (level > USER)
  1174.         strcpy(mail->from, argv[i]);
  1175.     } else if (!strcmp(">", argv[i])) {
  1176.       nextarg(">");
  1177.       strcpy(mail->to, argv[i]);
  1178.     } else if (!strcmp("@", argv[i])) {
  1179.       nextarg("@");
  1180.       strcpy(at, argv[i]);
  1181.     } else if (*mail->to && subject_in_send) {
  1182.       if (*argv[i] != '\032') { 
  1183.         if (*mail->subject) 
  1184.            strcat(mail->subject," "); 
  1185.         strcat(mail->subject,argv[i]);
  1186.       } else i++;
  1187.     }
  1188.     else  
  1189.       strcpy(mail->to, argv[i]);
  1190.  
  1191.   if (!*mail->to) {
  1192.     errors++;
  1193.     puts("No recipient specified.");
  1194.     free_mail(mail);
  1195.     return;
  1196.   }
  1197.   if (level == USER && !mail->to[1]) {
  1198.     errors++;
  1199.     puts("Invalid recipient specified.");
  1200.     free_mail(mail);
  1201.     return;
  1202.   }
  1203.   strcpy(mail->orig_to, mail->to);
  1204.   if (!callvalid(get_user_from_path(mail->to))){ 
  1205.     getalias(mail->to);
  1206.     if (!send_allowed(mail, at, myhostname)) {
  1207.        puts((level == MBOX) ? "NO" : "sorry");
  1208.        free_mail(mail);
  1209.        return ;
  1210.     }
  1211.   }
  1212.   
  1213.   mail->bin = 0;
  1214.     
  1215.   if (*at) {
  1216.     strcat(mail->to, "@");
  1217.     strcat(mail->to, at);
  1218.     strcat(mail->orig_to, "@");
  1219.     strcat(mail->orig_to, at);
  1220.   }
  1221.   
  1222.   strlwc(mail->to);
  1223.   strlwc(mail->orig_to);
  1224.   if (!*mail->from || level < MBOX) strcpy(mail->from, user.name);
  1225.  
  1226.   if (*mail->bid) {
  1227.     mail->bid[LEN_BID] = 0;
  1228.     strupc(mail->bid);
  1229.     if ((fdlock = lock_file(LOCKFILE, 0)) < 0) halt();
  1230.     unique = msg_uniq(mail->bid, mail->mid);
  1231.     close(fdlock);
  1232.     if (!unique) {
  1233.       puts("No");
  1234.       free_mail(mail);
  1235.       return;
  1236.     }
  1237.   }  
  1238.   if (level == MBOX) {
  1239.     if ((!strcmp(mail->to,"e@thebox") || !strcmp(mail->to,"m@thebox")) && 
  1240.          strlen(mail->subject)) {
  1241.       if (*path) {
  1242.         strcpy(line, mail->from);
  1243.         sprintf(mail->from, "%s!%s", path, line);
  1244.       }
  1245.       puts("OK");
  1246.       route_mail(mail);
  1247.       return;
  1248.     }
  1249.   }  
  1250.   if (!*mail->subject) {
  1251.     puts((level == MBOX) ? "OK" : "Enter subject:");
  1252.     if (!getstring(mail->subject)) exit(1);
  1253.     if (stopped) {
  1254.       free_mail(mail);
  1255.       return;
  1256.     }
  1257.   }  
  1258.   strtrim(mail->subject);
  1259.   if (!*mail->subject && level != MBOX) {
  1260.     errors++;
  1261.     puts("No subject specified.");
  1262.     free_mail(mail);
  1263.     return;
  1264.   }
  1265.   if (packetcluster || level != MBOX)
  1266.     printf("Enter message for %s: (terminate with ^Z or ***END)\n", 
  1267.             mail->orig_to);
  1268.  
  1269.   if (level != MBOX) {
  1270.     sprintf(line,"de %s",mail->from);
  1271.     append_line(mail,line);
  1272.     sprintf(line,"to %s",mail->orig_to);
  1273.     append_line(mail,line);
  1274.     append_line(mail,"");
  1275.   }
  1276.    
  1277.   for (; ; ) {
  1278.     if (!getstring(line)) exit(1);
  1279.     if (!strncmp(line,"#BIN#",5)) {
  1280. #ifdef BOXBIN    
  1281.       mail->bin = 1;
  1282.       i= send_binary(mail,line);
  1283.       if( !i ) {
  1284.         break ;
  1285.       }  else
  1286.       if (i == 1) 
  1287.       {
  1288.         mail->bin = 0;
  1289.       } else
  1290.       {
  1291.         free_mail(mail);
  1292.         return;
  1293.       } 
  1294. #else
  1295.     puts("#NO#");
  1296.     free_mail(mail);
  1297.     return;
  1298. #endif    
  1299.     } 
  1300.     if (stopped) {
  1301.       free_mail(mail);
  1302.       return;
  1303.     }
  1304.     if (*line == '\032') break;
  1305.     if (*line == '\001' && level != MBOX) {
  1306.       free_mail(mail);
  1307.       puts("aborted.");
  1308.       return;
  1309.     }  
  1310.     if (!Strncasecmp(line, "***end", 6)) break;
  1311.     if (!(check_header && line[0] == ' ' && line[1] == '[')) {
  1312.       append_line(mail, line);
  1313.       if (check_header) {
  1314.     if (p = get_host_from_header(line)) {
  1315.       if (*path) strcat(path, "!");
  1316.       strcat(path, p);
  1317.     } else if (*path)
  1318.       check_header = 0;
  1319.       }
  1320.     }
  1321.     if (strchr(line, '\032')) break;
  1322.   }
  1323.   if (*path) {
  1324.     strcpy(line, mail->from);
  1325.     sprintf(mail->from, "%s!%s", path, line);
  1326.   }
  1327.  
  1328.   if (level != MBOX) printf("Sending message to %s.\n", mail->to);
  1329.   route_mail(mail);
  1330. }
  1331.  
  1332. #undef nextarg
  1333.  
  1334. /*---------------------------------------------------------------------------*/
  1335.  
  1336. void set_command(int argc, char **argv)
  1337. {
  1338.   int i,j;
  1339.   char *errstr = "Syntax error. Type ? SET for help.";
  1340.  
  1341.   if(argc == 1) {
  1342.   
  1343.     printf("userinterface: ");
  1344.     if (interface_type == wampes)
  1345.       printf("wampes\n");
  1346.     else
  1347.     if (interface_type == diebox)
  1348.       printf("DieBox\n");
  1349.     else
  1350.       printf("unknown\n");
  1351.     if (interface_type == wampes) {
  1352.       printf("prompt: %s\n",prompt);  
  1353.       printf("escape character: %d\n", escape_char);
  1354. #ifdef BOXBIN
  1355.       printf("binary: %s\n", binary_allowed ? "yes" : "no");
  1356. #endif
  1357.       printf("subject in send command : %sallowed\n", 
  1358.                                         subject_in_send ? "" : "not ");
  1359.       printf("editor: %s\n", editor);
  1360.       printf("list last messages: %d\n", max_list);
  1361.       printf("fix address: %s\n", fix_allowed ? "yes" : "no");
  1362.     }
  1363.     if (level == ROOT) {
  1364.       printf("compress-program: %s\n",compress);
  1365.       printf("compress-extention: %s\n", compressext);
  1366.       printf("uncompress-option: %s\n", uncompressoption);
  1367.       printf("BBS-Administrator: %s\n", bbsadm);
  1368.       printf("domain: %s\n", mydomain);
  1369.       printf("hostname: %s\n", myhostname);
  1370.       printf("station is: %s\n", station);
  1371.       printf("debug mode: %s\n", (debug) ? "yes" : "no");
  1372.     }
  1373.  
  1374.     return ;
  1375.     
  1376.   }
  1377.   
  1378.   for (i=1; i < argc; i++) {
  1379. #ifdef BOXBIN  
  1380.     if (!Strncasecmp(argv[i],"binary",6) && (interface_type == wampes)) {
  1381.       binary_allowed=1;
  1382.     } else
  1383. #endif
  1384.     if (!Strncasecmp(argv[i],"fixaddress",6) && (interface_type == wampes)) {
  1385.       fix_allowed=1;
  1386.     } else    
  1387.     if (!Strncasecmp(argv[i],"subject",6) && (interface_type == wampes)) {
  1388.       subject_in_send=1;
  1389.     } else
  1390.     if (!Strncasecmp(argv[i],"editor",6) && (interface_type == wampes)) {
  1391.       i++;
  1392.       if (i == argc || *argv[i] != '=' ) {
  1393.         printf("%s\n",errstr);
  1394.         return;
  1395.       }
  1396.       if (++i == argc) {
  1397.         printf("%s\n",errstr);
  1398.         return;
  1399.       }
  1400.       strcpy(editor,argv[i]);
  1401.     } else
  1402.     if (!Strncasecmp(argv[i],"list",4) && (interface_type == wampes)) {
  1403.       i++;
  1404.       if (i == argc || *argv[i] != '=' ) {
  1405.         printf("%s\n",errstr);
  1406.         return;
  1407.       }
  1408.       if (++i == argc) {
  1409.         printf("%s\n",errstr);
  1410.         return;
  1411.       }
  1412.       max_list = atoi(argv[i]);
  1413.     } else    
  1414.     if (!Strncasecmp(argv[i],"escape",6) && (interface_type == wampes)) {
  1415.       i++;
  1416.       if (i == argc || *argv[i] != '=' ) {
  1417.         printf("%s\n",errstr);
  1418.         return;
  1419.       }
  1420.       if (++i == argc) {
  1421.         printf("%s\n",errstr);
  1422.         return;
  1423.       }
  1424.       if (!isdigit(*argv[i])) {
  1425.         printf("%s\n",errstr);
  1426.         return;
  1427.       }
  1428.       escape_char=Atoi(argv[i]);
  1429.     } else
  1430.     if (!Strncasecmp(argv[i],"interface",6)) {
  1431.       i++;
  1432.       if (i == argc || *argv[i] != '=' ) {
  1433.         printf("%s\n",errstr);
  1434.         return;
  1435.       }
  1436.       if (++i == argc) {
  1437.         printf("%s\n",errstr);
  1438.         return;
  1439.       }
  1440.       if (!Strcasecmp(argv[i],"wampes")) {
  1441.         strcpy(prompt,"bbsx> ");
  1442.         escape_char = orig_escape;
  1443.         binary_allowed = 0;
  1444.         subject_in_send =0;
  1445.         interface_type = wampes;
  1446.         free(alias_table);
  1447.         init_aliasdb();
  1448.       } else
  1449.       if (!Strcasecmp(argv[i],"diebox") || !Strcasecmp(argv[i],"thebox")) {
  1450.         strcpy(prompt,"(\\w) \\u de \\h>");
  1451.         escape_char = 10;
  1452.         binary_allowed = 1;
  1453.         subject_in_send = 1;
  1454.         interface_type = diebox;
  1455.         free(alias_table);
  1456.         init_aliasdb();
  1457.         insert_alias("CHECK","LIST NEW",0,1);
  1458.         insert_alias("FORWARD","MAIL",0,1);
  1459.         insert_alias("TRANSFER","MOVE",0,1);
  1460.         insert_alias("!","__",255,1);
  1461.         insert_alias("?","__",255,1);
  1462.         insert_alias("DELETE","_DELETE",255,1);
  1463.         insert_alias("DISCONNECT","_DISCONNECT",255,1);
  1464.         insert_alias("EXIT","_EXIT",255,1);
  1465.         insert_alias("INFO","_INFO",255,1);
  1466.         insert_alias("KILL","_KILL",255,1);
  1467.         insert_alias("MOVE","_MOVE",255,1);
  1468.         insert_alias("PRINT","_PRINT",255,1);
  1469.         insert_alias("RESPOND","_RESPOND",255,1);
  1470.         insert_alias("SHELL","_SHELL",255,1);
  1471.         insert_alias("SOURCE","_SOURCE",255,1);
  1472.         insert_alias("STATUS","_STATUS",255,1);
  1473.         insert_alias("TYPE","_TYPE",255,1);
  1474.         insert_alias("UNERASE","_UNERASE",255,1);
  1475.         insert_alias("UNSET","_UNSET",255,1);
  1476.         insert_alias("VERSION","_VERSION",255,1);
  1477.         insert_alias("WRITE","_WRITE",255,1);
  1478.         insert_alias("ALIAS","_ALIAS",255,1);
  1479.       } else
  1480.       {
  1481.         printf("%s\n",errstr);
  1482.         return;
  1483.       } 
  1484.     } else
  1485.     if (!Strcasecmp(argv[i],"prompt") && (interface_type == wampes)) {
  1486.       i++;
  1487.       if (i == argc || *argv[i] != '=' ) {
  1488.         printf("%s\n",errstr);
  1489.         return;
  1490.       }
  1491.       if (++i == argc) {
  1492.         printf("%s\n",errstr);
  1493.         return;
  1494.       }
  1495.       *prompt=0;
  1496.       for(j=i; j < argc; j++) {
  1497.           strcat(prompt,argv[j]);
  1498.       } 
  1499.     } else  {
  1500.       printf("What should I set ?\n");
  1501.       return;
  1502.     }   
  1503.   }
  1504.   
  1505.   return;
  1506. }
  1507.  
  1508.  
  1509. /*---------------------------------------------------------------------------*/
  1510.  
  1511. void sid_command(int argc, char **argv)
  1512. {
  1513.   #define DELIM "[]-"
  1514.  
  1515.   int i;
  1516.   char box_soft[16];
  1517.   char soft_ver[16];
  1518.   char flags[16];
  1519.   char password[20];
  1520.   char *f, *t, *s;
  1521.   char buf[1024];
  1522.   
  1523.   FILE *dbfp;
  1524.   FILE *pwdfp;
  1525.  
  1526.   f = argv[1];
  1527.   
  1528.   *box_soft = 0; 
  1529.   *soft_ver = 0; 
  1530.   *flags = 0; *buf = 0;
  1531.   s=buf;
  1532.   
  1533.   for(;;) {
  1534.      if (!*f) break;
  1535.      t=s;
  1536.      while (*f && !strchr(DELIM, *f)) *t++ = *f++;
  1537.      *t++ = 0;
  1538.      if (!*box_soft)
  1539.         strcpy(box_soft, buf);
  1540.      else
  1541.      if (strchr(buf, '$'))
  1542.         strcpy(flags, buf);
  1543.      else
  1544.      if(!*soft_ver)
  1545.         strcpy(soft_ver, buf);
  1546.      if (*f) f++;
  1547.   }
  1548.  
  1549.   if (argc > 3)
  1550.      strcpy(password, argv[3]);
  1551.  
  1552.   if (argc > 3) {
  1553.     if (doforward) {
  1554.        if (!get_passwd(user.name, password, boxpassword )) exit (0);
  1555.        password_ok = 1;
  1556.     }   
  1557.     else {
  1558.        if (strcmp(boxpassword, password)) exit (0); 
  1559.        password_ok = 1;
  1560.     }   
  1561.   }
  1562.   if (!Strcasecmp(box_soft,"thebox")) {
  1563.     if (!strcmp("1.9",soft_ver)) {
  1564.       binary_allowed = 1;
  1565.       subject_in_send = 1;
  1566.     }
  1567.     if (!strcmp("1.8",soft_ver)) {
  1568.       subject_in_send = 1;
  1569.     }  
  1570.   } else
  1571.   if (!Strcasecmp(box_soft,"baycom")) {
  1572.     if (!strcmp("1.14",soft_ver)) {
  1573.       subject_in_send = 1;
  1574.     }
  1575.     if (!strcmp("1.15",soft_ver)) {
  1576.       subject_in_send = 1;
  1577.     }
  1578.   }
  1579.   
  1580.   return;
  1581. }
  1582.  
  1583.  
  1584. /*---------------------------------------------------------------------------*/
  1585.  
  1586. void source_command(int argc, char **argv)
  1587. {
  1588.   FILE *fp;
  1589.   char line[1024];
  1590.   
  1591.   sprintf(line, "%s/%s", user.dir, argv[1]);
  1592.   if (fp = fopen(line, "r")) {
  1593.     while (fgets(line, sizeof(line), fp)) parse_command_line(line);
  1594.     fclose(fp);
  1595.   } else
  1596.     printf("can't open open file: %s\n",argv[1]);
  1597.     
  1598.   return;
  1599. }
  1600.  
  1601. /*---------------------------------------------------------------------------*/
  1602.  
  1603. void status_command(int argc, char **argv)
  1604. {
  1605.  
  1606.   int active = 0;
  1607.   int crunchok = 0;
  1608.   int deleted = 0;
  1609.   int highest = 0;
  1610.   int n;
  1611.   int new = 0;
  1612.   int readable = 0;
  1613.   long validdate;
  1614.   struct index *pi, index[1000];
  1615.  
  1616.   validdate = time((long *) 0) - 90 * DAYS;
  1617.   printf("BBSX  Revision: %s %s\n", BBSX_REVISION, REVISION_DATE);
  1618.   printf("BBSX based on DK5SG-BBS\n");
  1619.   if (lseek(fdindex, 0L, SEEK_SET)) halt();
  1620.   for (; ; ) {
  1621.     n = read(fdindex, pi = index, 1000 * sizeof(struct index)) / sizeof(struct index);
  1622.     if (n < 1) break;
  1623.     for (; n; n--, pi++) {
  1624.       highest = pi->mesg;
  1625.       if (pi->flags & DELETED) {
  1626.     deleted++;
  1627.     if (!*pi->bid || pi->date < validdate) crunchok++;
  1628.       } else {
  1629.     active++;
  1630.     if (read_allowed(pi)) {
  1631.       readable++;
  1632.       if (pi->mesg > user.seq) new++;
  1633.     }
  1634.       }
  1635.     }
  1636.   }
  1637.   printf("%6d  Highest message number\n", highest);
  1638.   printf("%6d  Active messages\n", active);
  1639.   printf("%6d  Readable messages\n", readable);
  1640.   if (level == ROOT) {
  1641.     printf("%6d  Deleted messages\n", deleted);
  1642.     printf("%6d  Messages may be crunched\n", crunchok);
  1643.   }
  1644.   printf("%6d  Last message listed\n", user.seq);
  1645.   printf("%6d  New messages\n", new);
  1646. }
  1647.  
  1648. /*---------------------------------------------------------------------------*/
  1649.  
  1650. void tell_command(int argc, char **argv)
  1651. {
  1652.  
  1653.   char *errstr = "Syntax Error.  Type ? TELL for help.\n";
  1654.   char at[1024];
  1655.   struct mail *mail;
  1656.   int i;
  1657.  
  1658.   mail = alloc_mail();
  1659.   *at = 0;
  1660.   if (argc < 3) {
  1661.     puts(errstr);
  1662.     free_mail(mail);
  1663.     return;
  1664.   }  
  1665.   if (!callvalid(get_host_from_path(argv[1])) ||
  1666.       strlen(argv[1]) < 4 ) {
  1667.     printf("Invalid Call: %s\n",argv[1]);
  1668.     free_mail(mail);
  1669.     return;
  1670.   }  
  1671.   strcpy(mail->to,"T");
  1672.   strcpy(at,argv[1]);
  1673.   strcat(mail->to, "@");
  1674.   strcat(mail->to, at);
  1675.   strlwc(mail->to);
  1676.   strcpy(mail->orig_to, mail->to);
  1677.  
  1678.   strcpy(mail->from, user.name);
  1679.   if (*mail->bid) {
  1680.     mail->bid[LEN_BID] = 0;
  1681.     strupc(mail->bid);
  1682.     if (!msg_uniq(mail->bid, mail->mid)) {
  1683.       puts("No");
  1684.       free_mail(mail);
  1685.       return;
  1686.     }
  1687.   }
  1688.   strcpy(mail->subject,argv[2]);  
  1689.   for(i=3;i < argc; i++) {
  1690.     strcat(mail->subject," ");
  1691.     strcat(mail->subject,argv[i]);
  1692.   }  
  1693.   printf("Tell is asking %s for command: %s\n", argv[1], mail->subject);
  1694.   strcat(mail->subject," @ ");
  1695.   strcat(mail->subject, Myhostname);
  1696.   route_mail(mail);
  1697. }
  1698.  
  1699. /*---------------------------------------------------------------------------*/
  1700.  
  1701. void undelete_command(int argc, char **argv)     
  1702. {
  1703.  
  1704.   int i;
  1705.   int mesg;
  1706.   struct index index;
  1707.   int max_mesg;
  1708.   int found = 0;
  1709.  
  1710.   max_mesg = get_highest_mesg(argc,argv);
  1711.   for (mesg = get_lowest_mesg(argc,argv); mesg <= max_mesg; mesg++)
  1712.     if (mesg_in_command(argc, argv, mesg, &index) &&
  1713.          !(index.flags & DELETED) &&
  1714.          strcmp(index.to,"B")) {
  1715.       found = 1;   
  1716.       if (level == ROOT                 ||
  1717.       calleq(index.from, user.name)) {
  1718.         index.date = time((long *) 0);
  1719.         strcpy(index.to,index.orig_to);
  1720.         getalias(index.to);
  1721.         if (lseek(fdindex, -sizeof(struct index), SEEK_CUR) < 0) halt();
  1722.         if (write(fdindex, &index, sizeof(struct index)) !=
  1723.             sizeof(struct index)) halt();
  1724.         printf("Message %d undeleted.\n", mesg);
  1725.       } else
  1726.           printf("Message %d not undeleted:  Permission denied.\n", mesg);
  1727.     }
  1728.   if (!found) {
  1729.      printf("No message found.\n");
  1730.   }  
  1731.   return;
  1732. }
  1733.  
  1734.  
  1735. /*---------------------------------------------------------------------------*/
  1736.  
  1737. void unknown_command(int argc, char **argv)
  1738. {
  1739.   errors++;
  1740.   printf("Unknown command '%s'.  Type ? for help.\n", *argv);
  1741. }
  1742.  
  1743. /*---------------------------------------------------------------------------*/
  1744.  
  1745. void unset_command(int argc, char **argv)
  1746. {
  1747.   int i;
  1748.  
  1749.   for (i=1; i < argc; i++) {
  1750. #ifdef BOXBIN  
  1751.     if (!Strncasecmp(argv[i],"binary",6)) 
  1752.       binary_allowed=0;
  1753.     else 
  1754. #endif    
  1755.     if (!Strncasecmp(argv[i],"subject",6)) 
  1756.       subject_in_send=0;
  1757.     else
  1758.     if (!Strncasecmp(argv[i],"fixaddress",6)) 
  1759.       fix_allowed=0;
  1760.     else 
  1761.       printf("There is no %s to unset.\n",argv[i]);
  1762.   }
  1763.   return;
  1764. }
  1765.  
  1766.  
  1767. /*---------------------------------------------------------------------------*/
  1768.  
  1769. void write_command(int argc, char **argv)
  1770. {
  1771.  
  1772.   int fp, wfp;
  1773.   char buffer[1024];
  1774.   char filename[512];
  1775.   int rd, wr;
  1776.   int mesg;
  1777.   struct index index;
  1778.   int i;
  1779.   int max_mesg;
  1780.   int found = 0;
  1781.   int bytes = 0;
  1782.   struct tm *tm;
  1783.   long now;
  1784.   char logfile[80];
  1785.   struct log log;
  1786.  
  1787.   now = time(0L);
  1788.   tm=gmtime(&now);
  1789.   sprintf(logfile,"%s%02d%02d.log",LOGFILE,tm->tm_year, tm->tm_mon); 
  1790.  
  1791.  
  1792.   if (argc < 3) {
  1793.     printf("Syntax error. Type ? WRITE for help.\n");
  1794.     return;
  1795.   }
  1796.   strcpy(filename,user.dir);
  1797.   strcat(filename,"/");
  1798.   strcat(filename,argv[1]);
  1799.      
  1800.   for (i = 2; i < argc; i++) 
  1801.     if ((mesg = Atoi(argv[i])) > 0 && get_index(mesg, &index) && 
  1802.          read_allowed(&index)) {
  1803.       found = 1; 
  1804.       bytes = 0;  
  1805.       if (!(wfp = open(filename, O_APPEND | O_WRONLY | O_CREAT, 0644))) halt();   
  1806.       if (!(fp = open(getfilename(mesg), O_RDONLY))) halt();
  1807.       sprintf(buffer,"\nMsg# %d   To: %s%s%s   From: %s   Date: %s\n",
  1808.           index.mesg,
  1809.           index.to,
  1810.           *index.at ? " @" : "",
  1811.           index.at,
  1812.           index.from,
  1813.           timestr(index.date));
  1814.       write(wfp,buffer,strlen(buffer));          
  1815.       if (*index.subject) sprintf(buffer,"Subject: %s\n", index.subject);
  1816.       write(wfp,buffer,strlen(buffer)); 
  1817.       if (*index.bid) sprintf(buffer,"Bulletin ID: %s\n", index.bid);
  1818.       write(wfp,buffer,strlen(buffer)); 
  1819.         
  1820.       do {
  1821.         rd=read(fp, buffer, 1024);
  1822.         wr=write(wfp, buffer, rd);
  1823.         bytes += rd;
  1824.         if (wr != rd) halt(); 
  1825.       } while (rd);  
  1826.       close(wfp); 
  1827.       close(fp);
  1828.       if (chown(filename, user.uid, user.gid)) halt() ;
  1829.       printf("wrote message %d to %s\n", mesg, filename);   
  1830.       if(log_reading && bytes && level == USER) {
  1831.         strcpy(log.to, index.to);
  1832.         log.bytes=bytes;
  1833.         log.uid = user.uid;
  1834.         log.time = time(0L);
  1835.         if ((fdlog = lock_file(LOCKFILE, 0)) < 0) halt();
  1836.         if (lseek(fdlog, 0L, SEEK_END) < 0) halt();
  1837.         if (write(fdlog, &log, sizeof(struct log)) != sizeof(struct log)) halt();
  1838.         close(fdlog);
  1839.       }
  1840.     }
  1841.     else
  1842.       printf("No such message: '%s'.\n", argv[i]);
  1843.   
  1844.   if (!found) {
  1845.      printf("No message found.\n");
  1846.   }
  1847.   return;
  1848. }
  1849.  
  1850.  
  1851. /*---------------------------------------------------------------------------*/
  1852.  
  1853. void xcrunch_command(int argc, char **argv)
  1854. {
  1855.  
  1856. #define TEMP_BID_DB     BID_DB ".tmp"
  1857. #define TEMP_INDEXFILE  INDEXFILE ".tmp"
  1858.  
  1859.   DBM * bid_db;
  1860.   datum datum_bid;
  1861.   datum datum_offset;
  1862.   int f;
  1863.   int wflag;
  1864.   long offset;
  1865.   long validdate;
  1866.   struct index index;
  1867.  
  1868.   validdate = time((long *) 0) - 90 * DAYS;
  1869.   if ((f = open(TEMP_INDEXFILE, O_WRONLY | O_CREAT | O_EXCL, 0644)) < 0) halt();
  1870.   if (lseek(fdindex, 0L, SEEK_SET)) halt();
  1871.   if (!(bid_db = dbm_open(TEMP_BID_DB, O_RDWR | O_CREAT, 0644))) halt();
  1872.   offset = 0;
  1873.   wflag = 0;
  1874.   while (read(fdindex, &index, sizeof(struct index)) == sizeof(struct index)) {
  1875.     wflag = 1;
  1876.     if (!(index.flags & DELETED) || *index.bid && index.date >= validdate) {
  1877.       if (write(f, &index, sizeof(struct index)) != sizeof(struct index)) halt();
  1878.       wflag = 0;
  1879.       if (*index.bid && index.date >= validdate) {
  1880.     datum_bid.dptr = index.bid;
  1881.     datum_bid.dsize = strlen(index.bid);
  1882.     datum_offset.dptr = (char *) &offset;
  1883.     datum_offset.dsize = sizeof(offset);
  1884.     if (dbm_store(bid_db, datum_bid, datum_offset, DBM_REPLACE) < 0) halt();
  1885.       }
  1886.       offset += sizeof(struct index);
  1887.     }
  1888.   }
  1889.   if (wflag)
  1890.     if (write(f, &index, sizeof(struct index)) != sizeof(struct index)) halt();
  1891.   if (close(f)) halt();
  1892.   dbm_close(bid_db);
  1893.   if (close(fdindex)) halt();
  1894.   if (rename(TEMP_INDEXFILE, INDEXFILE)) halt();
  1895.   if (rename(TEMP_BID_DB ".db", BID_DB ".db")) {
  1896.     if (rename(TEMP_BID_DB ".dir", BID_DB ".dir")) halt();
  1897.     if (rename(TEMP_BID_DB ".pag", BID_DB ".pag")) halt();
  1898.   }
  1899.   exit(0);
  1900. }
  1901.  
  1902. /*---------------------------------------------------------------------------*/
  1903.  
  1904. #define Invalid (                                   \
  1905.    (pi->flags & DELETED)                         || \
  1906.    *from    &&  strcmp(pi->from, from)           || \
  1907.    *to      &&  strcmp(pi->to,   to)             || \
  1908.    *at      &&  strcmp(pi->at,   at)             || \
  1909.    *subject && !strcasepos(pi->subject, subject)    \
  1910.    )
  1911.  
  1912. void xscreen_command(int argc, char **argv)
  1913. {
  1914.  
  1915.   FILE *fp = 0;
  1916.   char at[1024];
  1917.   char buf[1024];
  1918.   char from[1024];
  1919.   char subject[1024];
  1920.   char to[1024];
  1921.   int cmd;
  1922.   int indexarrayentries;
  1923.   int lines = 0;
  1924.   int maxlines;
  1925.   int mesg;
  1926.   struct index *indexarray;
  1927.   struct index *pi;
  1928.   struct stat statbuf;
  1929.   struct termios curr_termios, prev_termios;
  1930.   unsigned int indexarraysize;
  1931.  
  1932.   if (fstat(fdindex, &statbuf)) halt();
  1933.   indexarraysize = statbuf.st_size;
  1934.   indexarrayentries = indexarraysize / sizeof(struct index);
  1935.   if (!indexarrayentries) return;
  1936.   if (!(indexarray = malloc(indexarraysize))) halt();
  1937.   if (lseek(fdindex, 0L, SEEK_SET)) halt();
  1938.   if (read(fdindex, indexarray, indexarraysize) != indexarraysize) halt();
  1939.  
  1940.   tcgetattr(0, &prev_termios);
  1941.   curr_termios = prev_termios;
  1942.   curr_termios.c_iflag = BRKINT | ICRNL | IXON | IXANY | IXOFF;
  1943.   curr_termios.c_lflag = 0;
  1944.   curr_termios.c_cc[VMIN] = 1;
  1945.   curr_termios.c_cc[VTIME] = 0;
  1946.   tcsetattr(0, TCSANOW, &curr_termios);
  1947.   if (!(maxlines = Atoi(getenv("LINES")))) maxlines = 24;
  1948.  
  1949.   *from = *to = *at = *subject = 0;
  1950.   pi = indexarray;
  1951.   cmd = '\b';
  1952.   for (; ; ) {
  1953.     lines = 0;
  1954.     fflush(stdout);
  1955.     while (!cmd) cmd = getchar();
  1956.     switch (cmd) {
  1957.  
  1958.     case '\b':
  1959.       if (pi > indexarray) pi--;
  1960.       while (Invalid && pi > indexarray) pi--;
  1961.       while (Invalid && pi < indexarray + (indexarrayentries - 1)) pi++;
  1962.       cmd = Invalid ? 'q' : 'r';
  1963.       break;
  1964.  
  1965.     case 'k':
  1966.       if (unlink(getfilename(pi->mesg))) halt();
  1967.       pi->flags = pi->flags | DELETED;
  1968.       if (lseek(fdindex, (pi - indexarray) * sizeof(struct index), SEEK_SET) < 0) halt();
  1969.       if (write(fdindex, pi, sizeof(struct index)) != sizeof(struct index)) halt();
  1970.  
  1971.     case '\n':
  1972.       if (pi < indexarray + (indexarrayentries - 1)) pi++;
  1973.       while (Invalid && pi < indexarray + (indexarrayentries - 1)) pi++;
  1974.       while (Invalid && pi > indexarray) pi--;
  1975.       cmd = Invalid ? 'q' : 'r';
  1976.       break;
  1977.  
  1978.     case 'r':
  1979.       if (fp) {
  1980.     fclose(fp);
  1981.     fp = 0;
  1982.       }
  1983.       if (!(fp = fopen(getfilename(pi->mesg), "r"))) halt();
  1984.       printf("\033&a0y0C\033JMsg# %d   To: %s%s%s   From: %s   Date: %s\n", pi->mesg, pi->to, *pi->at ? " @" : "", pi->at, pi->from, timestr(pi->date));
  1985.       lines++;
  1986.       if (*pi->subject) {
  1987.     printf("Subject: %s\n", pi->subject);
  1988.     lines++;
  1989.       }
  1990.       if (*pi->bid) {
  1991.     printf("Bulletin ID: %s\n", pi->bid);
  1992.     lines++;
  1993.       }
  1994.       putchar('\n');
  1995.       lines++;
  1996.  
  1997.     case ' ':
  1998.       if (fp) {
  1999.     while (lines < maxlines - 1 && fgets(buf, sizeof(buf), fp)) {
  2000.       fputs(buf, stdout);
  2001.       lines++;
  2002.     }
  2003.     if (feof(fp)) {
  2004.       fclose(fp);
  2005.       fp = 0;
  2006.     }
  2007.     cmd = 0;
  2008.       } else
  2009.     cmd = '\n';
  2010.       break;
  2011.  
  2012.     case '0':
  2013.     case '1':
  2014.     case '2':
  2015.     case '3':
  2016.     case '4':
  2017.     case '5':
  2018.     case '6':
  2019.     case '7':
  2020.     case '8':
  2021.     case '9':
  2022.       tcsetattr(0, TCSANOW, &prev_termios);
  2023.       printf("\nMessage number: %c", cmd);
  2024.       *buf = cmd;
  2025.       gets(buf + 1);
  2026.       tcsetattr(0, TCSANOW, &curr_termios);
  2027.       mesg = Atoi(buf);
  2028.       pi = indexarray;
  2029.       while ((mesg > pi->mesg || Invalid) && pi < indexarray + (indexarrayentries - 1)) pi++;
  2030.       while (Invalid && pi > indexarray) pi--;
  2031.       cmd = Invalid ? 'q' : 'r';
  2032.       break;
  2033.  
  2034.     case '<':
  2035.       *from = *to = *at = *subject = 0;
  2036.       tcsetattr(0, TCSANOW, &prev_termios);
  2037.       printf("\nFROM field: ");
  2038.       gets(from);
  2039.       tcsetattr(0, TCSANOW, &curr_termios);
  2040.       strupc(from);
  2041.       cmd = Invalid ? '\n' : 'r';
  2042.       break;
  2043.  
  2044.     case '>':
  2045.       *from = *to = *at = *subject = 0;
  2046.       tcsetattr(0, TCSANOW, &prev_termios);
  2047.       printf("\nTO field: ");
  2048.       gets(to);
  2049.       tcsetattr(0, TCSANOW, &curr_termios);
  2050.       strupc(to);
  2051.       cmd = Invalid ? '\n' : 'r';
  2052.       break;
  2053.  
  2054.     case '@':
  2055.       *from = *to = *at = *subject = 0;
  2056.       tcsetattr(0, TCSANOW, &prev_termios);
  2057.       printf("\nAT field: ");
  2058.       gets(at);
  2059.       tcsetattr(0, TCSANOW, &curr_termios);
  2060.       strupc(at);
  2061.       cmd = Invalid ? '\n' : 'r';
  2062.       break;
  2063.  
  2064.     case 's':
  2065.       *from = *to = *at = *subject = 0;
  2066.       tcsetattr(0, TCSANOW, &prev_termios);
  2067.       printf("\nSUBJECT substring: ");
  2068.       gets(subject);
  2069.       tcsetattr(0, TCSANOW, &curr_termios);
  2070.       cmd = Invalid ? '\n' : 'r';
  2071.       break;
  2072.  
  2073.     case 'v':
  2074.       sprintf(buf, "%s %s", editor, getfilename(pi->mesg));
  2075.       tcsetattr(0, TCSANOW, &prev_termios);
  2076.       system(buf);
  2077.       tcsetattr(0, TCSANOW, &curr_termios);
  2078.       cmd = 'r';
  2079.       break;
  2080.  
  2081.     case 'q':
  2082.       tcsetattr(0, TCSANOW, &prev_termios);
  2083.       free(indexarray);
  2084.       return;
  2085.  
  2086.     case '?':
  2087.       puts("----------------------------------- Commands ----------------------------------");
  2088.  
  2089.       puts("<          specify FROM field");
  2090.       puts("<number>   show numbered entry");
  2091.       puts(">          specify TO field");
  2092.       puts("?          print command summary");
  2093.       puts("@          specify AT field");
  2094.       puts("BACKSPACE  show previous entry");
  2095.       puts("RETURN     show next entry");
  2096.       puts("SPACE      show next screenful");
  2097.       puts("k          delete current entry");
  2098.       puts("q          quit screen mode");
  2099.       puts("r          redisplay current entry");
  2100.       puts("s          specify SUBJECT substring");
  2101.       puts("v          edit current entry");
  2102.  
  2103.       printf("\nPress any key to continue ");
  2104.       getchar();
  2105.       cmd = 'r';
  2106.       break;
  2107.     default:
  2108.       putchar('\007');
  2109.       cmd = 0;
  2110.       break;
  2111.     }
  2112.   }
  2113. }
  2114.  
  2115. #undef Invalid
  2116.